package driver

import (
	"context"
	"fmt"
	"log"
	"math"

	"cloudea.com/k8s-csi-fs/driver/proto"
	"cloudea.com/k8s-csi-fs/driver/utils"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

type ControllerServer struct {
	proto.UnimplementedControllerServer
}

const B = 1
const K = 1024 * B
const M = 1024 * K
const G = 1024 * M
const T = 1024 * G

func (ControllerServer) CreateVolume(context context.Context, query *proto.CreateVolumeRequest) (*proto.CreateVolumeResponse, error) {
	name := query.Name
	limit := query.CapacityRange.GetLimitBytes()      // 可选参数
	require := query.CapacityRange.GetRequiredBytes() // 可选参数
	capabilities := query.VolumeCapabilities          // 这个参数先不管

	if name == "" {
		log.Println("CreateVolume: Volume 名字需要提供")
		return nil, status.Error(codes.InvalidArgument, "Volume 名字需要提供")
	}

	capacity := int(math.Ceil(math.Max(float64(float64(limit)), float64(require))))
	if capacity == 0 {
		capacity = 100 * M
	}

	if len(capabilities) == 0 {
		log.Println("CreateVolume: 需要提供Volume能力")
		return nil, status.Error(codes.InvalidArgument, "需要提供Volume能力")
	}

	volumeId := fmt.Sprintf("%v", utils.StringCRC32Hash(name))
	if volumeId == "0" {
		log.Print("volumeId不能为0, name=%v, volumeId=%v \n", name, volumeId)
		return nil, status.Error(codes.InvalidArgument, "volumeId不能为0")
	}

	resp := &proto.CreateVolumeResponse{
		Volume: &proto.Volume{
			CapacityBytes: int64(capacity),
			VolumeId:      volumeId,
		},
	}

	if v, err := GetVolume(volumeId); err == nil {
		if v.GetCapacityBytes() != int64(capacity) {
			msg := fmt.Sprintf("CreateVolume: name=%v, volumeId=%v 已存在, 但是容量不一致 \n", name, volumeId)
			log.Print(msg)
			return nil, status.Error(codes.AlreadyExists, msg)
		}
		return resp, nil
	}

	if err := CreateVolume(volumeId, capacity); err == nil {

		log.Printf("CreateVolume: 被调用 name = %s, limit = %d, require = %d, len(capabilities) = %d, volumeId=%v \n",
			name,
			limit,
			require,
			len(capabilities),
			volumeId,
		)
		return resp, nil
	} else {
		log.Println("CreateVolume: " + err.Error())
		return nil, status.Errorf(codes.Internal, err.Error())
	}
}

func (ControllerServer) DeleteVolume(context context.Context, query *proto.DeleteVolumeRequest) (*proto.DeleteVolumeResponse, error) {
	volumeId := query.GetVolumeId()
	if volumeId == "" {
		msg := fmt.Sprintf("DeleteVolume: 卷id不能为空 \n")
		log.Print(msg)
		return nil, status.Errorf(codes.InvalidArgument, msg)
	}
	if err := DeleteVolume(volumeId); err == nil {
		resp := &proto.DeleteVolumeResponse{}
		log.Printf("DeleteVolume: volumeId=%s\n", volumeId)
		return resp, nil
	} else {
		log.Println("DeleteVolume:" + err.Error())
		return nil, status.Errorf(codes.Internal, err.Error())
	}
}

func (ControllerServer) ControllerPublishVolume(context context.Context, query *proto.ControllerPublishVolumeRequest) (*proto.ControllerPublishVolumeResponse, error) {
	volumeId := query.GetNodeId()
	nodeId := query.GetNodeId()
	capability := query.GetVolumeCapability()
	if volumeId == "" || nodeId == "" || capability == nil {
		log.Printf("ControllerPublishVolume: 参数错误 volumeId=%s, nodeId=%s, capability=%v",
			volumeId,
			nodeId,
			capability,
		)
		return nil, status.Error(codes.InvalidArgument, "ControllerPublishVolume: 参数错误")
	}
	if volumeId == "0" {
		// TODO: for appeasing test suite bug
		return &proto.ControllerPublishVolumeResponse{}, nil
	}
	if _, err := GetVolume(volumeId); err != nil || nodeId != "0" {
		msg := fmt.Sprintf("ControllerPublishVolume: 卷或结点不存在 volumeId=%v, nodeId=%v \n",
			volumeId,
			nodeId,
		)
		log.Print(msg)
		return nil, status.Error(codes.NotFound, msg)
	}

	log.Printf("ControllerPublishVolume:  volumeId=%s, nodeId=%s, capability=%v",
		volumeId,
		nodeId,
		capability,
	)
	resp := &proto.ControllerPublishVolumeResponse{}
	return resp, nil
}

func (ControllerServer) ControllerUnpublishVolume(context context.Context, query *proto.ControllerUnpublishVolumeRequest) (*proto.ControllerUnpublishVolumeResponse, error) {
	volumeId := query.GetNodeId()
	nodeId := query.GetNodeId() // 可选参数
	if volumeId == "" {
		log.Printf("ControllerUnpublishVolume: 参数错误 volumeId=%s, nodeId=%s \n",
			volumeId,
			nodeId,
		)
		return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("ControllerUnpublishVolume: 参数错误: volumeId = %s, nodeId = %s", volumeId, nodeId))
	}
	log.Printf("ControllerUnpublishVolume: volumeId=%s, nodeId=%s \n",
		volumeId,
		nodeId,
	)
	resp := &proto.ControllerUnpublishVolumeResponse{}
	return resp, nil
}

/** 对Context、prameter、volumeCapabilies这三项进行验证 */
func (ControllerServer) ValidateVolumeCapabilities(context context.Context, query *proto.ValidateVolumeCapabilitiesRequest) (*proto.ValidateVolumeCapabilitiesResponse, error) {
	volumeId := query.GetVolumeId()
	volumeCapabilies := query.GetVolumeCapabilities()
	if volumeId == "" || volumeCapabilies == nil {
		log.Printf("ValidateVolumeCapabilities: 参数错误 volumeId=%v, volumeCapabilies=%v \n",
			volumeId,
			volumeCapabilies,
		)
		return nil, status.Error(codes.InvalidArgument, "ValidateVolumeCapabilities: 参数错误")
	}

	if _, err := GetVolume(volumeId); err != nil {
		msg := fmt.Sprintf("ValidateVolumeCapabilities: 卷不存在 volumeId=%v \n",
			volumeId,
		)
		log.Print(msg)
		return nil, status.Error(codes.NotFound, msg)
	}

	// 默认通过
	resp := &proto.ValidateVolumeCapabilitiesResponse{
		Confirmed: &proto.ValidateVolumeCapabilitiesResponse_Confirmed{
			VolumeContext:      query.VolumeContext,
			Parameters:         query.Parameters,
			VolumeCapabilities: volumeCapabilies,
		},
		Message: "卷能力确认成功",
	}
	log.Printf("ValidateVolumeCapabilities: volumeId=%v, volumeCapabilies=%v \n",
		volumeId,
		volumeCapabilies,
	)
	return resp, nil
}

func (ControllerServer) ListVolumes(context context.Context, query *proto.ListVolumesRequest) (*proto.ListVolumesResponse, error) {
	pageSize := query.GetMaxEntries()
	startToken := query.GetStartingToken()
	if pageSize == 0 {
		pageSize = (1 << 31) - 1
	}

	volumes, err := ListVolumes()
	var entries []*proto.ListVolumesResponse_Entry
	var started bool = startToken == ""
	var nextToken = ""
	if err == nil {
		for i := 0; i < len(volumes); i++ {
			if volumes[i].VolumeId == startToken {
				started = true
			}
			if started {
				entries = append(entries, &proto.ListVolumesResponse_Entry{
					Volume: &volumes[i],
				})
				if len(entries) >= int(pageSize) {
					if i+1 < len(volumes) {
						nextToken = volumes[i+1].VolumeId
					}
					break
				}
			}
		}
	}
	if startToken != "" && len(entries) == 0 {
		msg := fmt.Sprintf("ListVolumes: next token 错误 pageSize=%v, startingToken=%v \n", pageSize, startToken)
		log.Print(msg)
		return nil, status.Errorf(codes.Aborted, msg)
	}
	log.Printf("ListVolumes: len(entries)=%d \n",
		len(entries),
	)
	resp := &proto.ListVolumesResponse{
		Entries:   entries,
		NextToken: nextToken,
	}
	return resp, nil
}

/** 返回存储池的容量 */
func (ControllerServer) GetCapacity(context.Context, *proto.GetCapacityRequest) (*proto.GetCapacityResponse, error) {
	resp := &proto.GetCapacityResponse{
		AvailableCapacity: GetAvailableCapacity(),
	}
	log.Printf("GetCapacity: availableCapacity=%d \n",
		resp.AvailableCapacity,
	)
	return resp, nil
}

func (ControllerServer) ControllerGetCapabilities(context.Context, *proto.ControllerGetCapabilitiesRequest) (*proto.ControllerGetCapabilitiesResponse, error) {
	resp := &proto.ControllerGetCapabilitiesResponse{
		Capabilities: []*proto.ControllerServiceCapability{
			{
				Type: &proto.ControllerServiceCapability_Rpc{
					Rpc: &proto.ControllerServiceCapability_RPC{
						Type: proto.ControllerServiceCapability_RPC_CREATE_DELETE_VOLUME,
					},
				},
			},
			{
				Type: &proto.ControllerServiceCapability_Rpc{
					Rpc: &proto.ControllerServiceCapability_RPC{
						Type: proto.ControllerServiceCapability_RPC_PUBLISH_UNPUBLISH_VOLUME,
					},
				},
			},
			{
				Type: &proto.ControllerServiceCapability_Rpc{
					Rpc: &proto.ControllerServiceCapability_RPC{
						Type: proto.ControllerServiceCapability_RPC_LIST_VOLUMES,
					},
				},
			},
			{
				Type: &proto.ControllerServiceCapability_Rpc{
					Rpc: &proto.ControllerServiceCapability_RPC{
						Type: proto.ControllerServiceCapability_RPC_GET_CAPACITY,
					},
				},
			},
		},
	}
	log.Printf("ControllerGetCapabilities: len(capabilities)=%d, capabilities=%v\n",
		len(resp.Capabilities),
		resp.Capabilities,
	)
	return resp, nil
}

func (ControllerServer) ControllerGetVolume(context context.Context, query *proto.ControllerGetVolumeRequest) (*proto.ControllerGetVolumeResponse, error) {
	volumeId := query.GetVolumeId()
	if volumeId == "" {
		log.Printf("ControllerGetVolume: 参数错误 volumeId=%s\n",
			volumeId,
		)
		return nil, status.Errorf(codes.InvalidArgument, "ControllerGetVolume: 参数错误")
	}

	volume, err := GetVolume(volumeId)
	if err != nil {
		log.Printf("ControllerGetVolume: 内部错误 %v\n",
			err,
		)
		return nil, status.Errorf(codes.Unavailable, err.Error())
	}

	resp := &proto.ControllerGetVolumeResponse{
		Volume: volume,
		Status: &proto.ControllerGetVolumeResponse_VolumeStatus{
			// 参数是 optional
		},
	}
	log.Printf("ControllerGetVolume: volumeId=%s, resp=%v\n",
		volumeId,
		resp,
	)
	return resp, nil
}
